// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	10/9/2014 12:07:25 PM				
// -----------------------------

#include "Window.h"
#include "Application.h"
#include "RenderManager.h"

Window::Window(Application* lpApp)
	: m_lpApp(lpApp)
	, m_hWindow(NULL)
	, m_IsAlive(false)
	, m_IsActive(false)
	, m_Caption(_T(""))
	, m_Width(0)
	, m_Height(0)
	, m_IsFullscreen(false)
	, m_dwWindowStyle(WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU)
{
}

Window::~Window()
{
}
Bool Window::Init(GameConfig& config)
{
	// Save the Settings
	m_Caption = config.Caption;
	m_Width = config.Width;
	m_Height = config.Height;
	m_IsFullscreen = config.Fullscreen;

	// Create the Window Class
	WNDCLASS wndClass = {};
	wndClass.hInstance = GetModuleHandle(NULL);
	wndClass.lpfnWndProc = Window::WndProcWrapper;
	wndClass.lpszClassName = m_Caption.c_str();
	wndClass.hIcon = NULL;
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)BLACK_BRUSH;

	// Register the Window Class
	Log::WriteLine(_T("[WINDOW]\tRegistering Window Class."));
	if (!RegisterClass(&wndClass))
		return false;

	// Calculate the Window Dimensions
	Log::WriteLine(_T("[WINDOW]\tCalculating Window Dimensions."));
	DWORD dwStyle = 0;
	RECT wndRect = {};
	dwStyle = WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU;
	wndRect.left = (GetSystemMetrics(SM_CXSCREEN) - m_Width) / 2;
	wndRect.top = (GetSystemMetrics(SM_CYSCREEN) - m_Height) / 2;
	wndRect.right = wndRect.left + m_Width;
	wndRect.bottom = wndRect.top + m_Height;
	AdjustWindowRect(&wndRect, dwStyle, FALSE);
	Log::WriteLine(_T("[WINDOW]\tWindow Dimensions (%u, %u, %u, %u)"), wndRect.left, wndRect.top, wndRect.right, wndRect.bottom);

	// Create the Window
	Log::WriteLine(_T("[WINDOW]\tCreating Window Handle."));
	m_hWindow = CreateWindow(wndClass.lpszClassName, wndClass.lpszClassName,
		dwStyle, wndRect.left, wndRect.top, wndRect.right - wndRect.left,
		wndRect.bottom - wndRect.top, NULL, NULL, wndClass.hInstance, this);
	if (!m_hWindow)
		return false;

	// Show & Update the Window
	ShowWindow(m_hWindow, SW_SHOW);
	UpdateWindow(m_hWindow);

	// Set the Window to Alive
	m_IsAlive = true;
	
	return true;
}

LRESULT WINAPI Window::WndProcWrapper(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	Window* lpWindow = nullptr;
	// Check if Create Message
	if (uMsg == WM_NCCREATE)
	{
		// Get the 'this' parameter
		CREATESTRUCT* lpCreateStruct = reinterpret_cast<CREATESTRUCT*>(lParam);
		lpWindow = reinterpret_cast<Window*>(lpCreateStruct->lpCreateParams);
		// Save the Pointer
		SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)lpWindow);
	}
	// Else, get the Window
	else
		lpWindow = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));

	// Call the Proc if valid
	// Else, pass the default message
	if (lpWindow)
		return lpWindow->WndProc(hWnd, uMsg, wParam, lParam);
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
LRESULT Window::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	// Handle the Message
	switch (uMsg)
	{
		// Window Close/Destroy
		case WM_DESTROY:
		{
			Log::WriteLine(_T("[WINDOW]\tEVENT: Destroying Window."));
			m_IsAlive = false;
			return 0;
		}
		// Window Activate/Deactivate
		case WM_ACTIVATE:
		{
			if (wParam == WA_INACTIVE)
				m_IsActive = false;
			else
				m_IsActive = true;
			Log::WriteLine(_T("[WINDOW]\tEVENT: Window Active State changed. (isActive=%u)"), m_IsActive);
			return 0;
		}
		// Window Resize
		case WM_SIZE:
		{
			// Make sure that it's not the resize
			// at the end of the game
			if (!m_IsAlive)
				return 0;

			// Get the new Width & Height
			RECT clientRect = {};
			GetClientRect(hWnd, &clientRect);
			m_Width = clientRect.right - clientRect.left;
			m_Height = clientRect.bottom - clientRect.top;

			Log::WriteLine(_T("[WINDOW]\tEVENT: Resizing Window. (%ux%u)"), m_Width, m_Height);

			if (m_lpApp->GetRenderer())
				m_lpApp->GetRenderer()->Resize(m_lpApp);

			return 0;
		}
	}

	// Return the Default Message if not handled
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

Bool Window::HandleMessages() const
{
	MSG msg = {};
	if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);

		return true;
	}
	return false;
}

Bool Window::IsAlive() const
{
	return m_IsAlive;
}
Bool Window::IsActive() const
{
	return m_IsActive;
}

HWND Window::GetHandle() const
{
	return m_hWindow;
}
UInt32 Window::GetWidth() const
{
	return m_Width;
}
UInt32 Window::GetHeight() const
{
	return m_Height;
}
Bool Window::IsFullscreen() const
{
	return m_IsFullscreen;
}